package com.anxinr.interceptor;

import com.mysql.cj.jdbc.ConnectionImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
 * @author anxinr
 * @describe sql拦截
 */
@Slf4j
@Intercepts({
        @Signature(
                type = Executor.class,
                method = "query",
                args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}
        ),
        @Signature(
                type = Executor.class,
                method = "update",
                args = {MappedStatement.class,Object.class}
        ),
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )
})
public class MybatisSqlInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable{
        ConnectionImpl target = (ConnectionImpl) invocation.getTarget();

        System.out.println("target.getClass() = " + target.getClass());
        for (int i = 0; i < invocation.getArgs().length; i++) {
            System.out.println("invocation.getArgs()[i] = " + invocation.getArgs()[i]);
            System.out.println("invocation.getMethod().getName() = " + invocation.getMethod().getName());
            boolean result = invocation.getArgs()[i] instanceof MappedStatement;
            if (result){
                MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[i];
                /**sqlsource  就是你目前拦截到的sql语句的实体类*/
                System.out.println("mappedStatement.getSqlSource() = " + mappedStatement.getSqlSource());
                BoundSql boundSql = mappedStatement.getBoundSql(mappedStatement.getSqlSource());
                /**这里获取到具体的sql语句*/
                System.out.println("boundSql.getSql() = " + boundSql.getSql());
                /**通过反射，暴力修改final修饰的字段属性   */
                Field sqlBean = boundSql.getClass().getDeclaredField("sql");
                String sql = boundSql.getSql();
                /**开启直接修改final修饰的字段*/
                sqlBean.setAccessible(true);
                sqlBean.set(boundSql,sql);
                log.info("执行的sql是 -> {}",sql);
            }
        }
        return invocation.getMethod().invoke(invocation.getTarget(),invocation.getArgs());
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // NOP
    }
}
